%{


#include <assert.h>
#include "list/quadList.h"
#include "list/symbolList.h"
#include "list/intList.h"

#include "errorHandler.h"
#include "code.h"
#include "symbolTable.h"
#include "symbol.h"
#include "quad.h"
#include <stdio.h>
#include <stdlib.h>

int yylex ();
void yyerror(const char* err);
int yydebug=1;

 extern unsigned long int NEXTQUAD;
%}

%start PROGRAM

 /**********************************************************************************************/
 /**********************************************************************************************/
 /**********************************************************************************************/
 /************************************ TOKEN DECLARATION ***************************************/
 /**********************************************************************************************/
 /**********************************************************************************************/
 /**********************************************************************************************/
%token tok_KWbool tok_KWint 
%token tok_add tok_KWand tok_orOr tok_andAnd  tok_div tok_minus tok_mul tok_not
%token tok_begin tok_end tok_let tok_in  tok_ref tok_rec
%token tok_colon tok_sep tok_op tok_cp   tok_dot 
%token tok_else tok_if tok_then 
%token tok_exclam tok_leftArrow
%token tok_array tok_do tok_done tok_while
%token tok_printInt tok_printString  tok_readInt  tok_makeArray
%token tok_aff

%token<strVal> tok_string tok_ident 
%token<intVal> tok_true tok_false tok_num 
%token<relVal> tok_rel 

%left EXPRLIST_REDUCE
%left FUNC_CALL_REDUCE
%left NO_ELSE_REDUCE
%left tok_aff
/* caml is right associative with functions as well */
/* so identifiers are right associative */
%right tok_ident
%right tok_else

/* shift for exprlist reduce */
%right tok_true tok_false tok_num tok_op tok_exclam tok_readInt 

/* operator */
%left tok_printInt
%left tok_add tok_minus 
%left tok_mul tok_div

%left tok_rel tok_eq
%left tok_andAnd tok_orOr
%left tok_KWand
%left tok_not

/* if is non assoc: indeed "toto if true then 2" is syntactically incorrect */
%nonassoc tok_if

 /**********************************************************************************************/
 /**********************************************************************************************/
 /**********************************************************************************************/
 /**************************************** TYPES ***********************************************/
 /**********************************************************************************************/
 /**********************************************************************************************/
 /**********************************************************************************************/
%union {
  struct exprval
  {
    intList truelist;
    intList falselist;
    symbol* ptrVal;
    enum val_t valType;
  } exprVal;
  struct instrVal {
    intList nextlist;
  } instrVal;
  enum quad_t relVal;
  unsigned long int nextquadPtr;
  int intVal;
  char* strVal;
  enum val_t typeVal;
  struct funDefVal {
    enum val_t retType;
    unsigned int numberOfParam;
  } funDefVal;
  struct exprlistVal {
    unsigned long int number;
    intList nextlist;
  } exprlistVal;
  /* for arguments */
  symbol symVal;
  struct elem_symbol* symlistVal;
  struct valcst_t
  {
    symbol* ptrVal;
    unsigned int size;
  } valcstVal;
  symbol* ptrVal;
}

%type<exprVal> EXPR 
%type<nextquadPtr> M
%type<instrVal> INSTR SEQUENCE PROCCALL
%type<typeVal> TYPE ATOMICTYPE
%type<funDefVal> FUNDEF 
%type<symlistVal> ARGLIST1
%type<symVal> ARG
%type<exprlistVal> EXPRLIST
%type<ptrVal> ATOMICCST VALCST
%%

M : %prec EXPRLIST_REDUCE  {
  $$=NEXTQUAD;
 }

PROGRAM : DECLLIST M INSTR tok_sep tok_sep {
  /* add the last quad and backpatch remaining quads */
  backpatch($3.nextlist,gen(newQuad(Q_END,NULL,NULL,NULL)));
  /* set entry point of the program to point just before begining of instruction */
  setEntryPoint($2);
 }


DECLLIST : ;
| DECL tok_in DECLLIST


VARDECLLIST : ; 
| VARDECL tok_in VARDECLLIST 

DECL : VARDECL 
| FUNDECL 

VARDECL : tok_let tok_ident tok_colon TYPE tok_eq VALCST {
  if(searchSymbol($2)!=SYMBOL_NOT_FOUND)
    {
      error(SYMBOL,SYMBOL_NOT_FOUND,__LINE__);
    }
  symbol* ptr=addSymbol(newSymbol(S_ID,$2,$4));
  /* if it is an array, set size */
  setSizeVal(ptr,$6->size);
  /* assign our ptr to the const */
  gen(newQuad(Q_ASSIGN,$6,NULL,ptr));
}
|  tok_let tok_ident tok_colon ATOMICTYPE tok_ref tok_eq tok_ref ATOMICCST {
  if(searchSymbol($2)!=SYMBOL_NOT_FOUND)
    {
      error(SYMBOL,SYMBOL_NOT_FOUND,__LINE__);
    }
  symbol* ptr;
  if($4==TYPE_INT)
    ptr=addSymbol(newSymbol(S_ID,$2,TYPE_INT_REF));
  else
    ptr=addSymbol(newSymbol(S_ID,$2,TYPE_BOOL_REF));
  /* here is a pointer assignement */
  gen(newQuad(Q_PTASSIGN,$8,NULL,ptr));

}

FUNDECL : tok_let FUNDEF {
  gen(newQuad(Q_FUNCEND,NULL,NULL,NULL));
}
| tok_let tok_rec FUNDEFS {
  gen(newQuad(Q_FUNCEND,NULL,NULL,NULL));
}

FUNDEFS :  FUNDEF {
  /* not much */
  }
| FUNDEF tok_KWand FUNDEFS {
  /* tough one... */
  }

FUNDEF :  tok_ident M ARGLIST tok_eq VARDECLLIST INSTR {
  if(searchSymbol($1)!=SYMBOL_NOT_FOUND)
    {
      error(SYMBOL,SYMBOL_NOT_FOUND,__LINE__);
    }
  /* just recognize a function: we pop the context such that we don't know  */
  /* local variable anymore */
  popContext();
  
  symbol* pts=addSymbol(newSymbol(S_ID,$1,TYPE_UNIT));
  pts->quadRef=$2;
}
|  tok_ident M ARGLIST tok_colon ATOMICTYPE tok_eq VARDECLLIST INSTR tok_sep EXPR {
  if(searchSymbol($1)!=SYMBOL_NOT_FOUND)
    {
      error(SYMBOL,SYMBOL_NOT_FOUND,__LINE__);
    }
  /* just recognize a function: we pop the context such that we don't know  */
  /* local variable anymore */
  popContext();

/* TOO LATE: this have to be done before code generation */
  symbol* pts=addSymbol(newSymbol(S_ID,$1,$10.valType));
  pts->quadRef=$2;
}
|  tok_ident M ARGLIST tok_colon ATOMICTYPE tok_eq VARDECLLIST EXPR {
  if(searchSymbol($1)!=SYMBOL_NOT_FOUND)
    {
      error(SYMBOL,SYMBOL_NOT_FOUND,__LINE__);
    }
  /* just recognize a function: we pop the context such that we don't know  */
  /* local variable anymore */
  popContext();
  
  /* TOO LATE: this have to be done before code generation */
  symbol* pts=addSymbol(newSymbol(S_ID,$1,$8.valType));
  pts->quadRef=$2;
}

TYPE :  ATOMICTYPE 
| ATOMICTYPE tok_array {
  if($1==TYPE_BOOL)
    $$=TYPE_BOOL_ARRAY;
  else
    $$=TYPE_INT_ARRAY;
}

ATOMICTYPE :  tok_KWbool {
  $$=TYPE_BOOL;
}
| tok_KWint {
  $$=TYPE_INT;
  }

VALCST :  ATOMICCST {
    $$=$1;
}
| tok_makeArray tok_num ATOMICCST {
  /* an array of num is created: the type is "altered" from built-in to array */
    switch($3->type)
      {
      case (TYPE_INT):
	{
	  $$=newTmp(TYPE_INT_ARRAY);
	}
      break;
      case (TYPE_BOOL):
	{
	  $$=newTmp(TYPE_BOOL_ARRAY);
	}
      break;
      }
    setSizeVal($$,(unsigned int)$2);
    int i=0;
    for (i=0;i<$2;i++)
      {
	/* we assign cells of the array to the desired atomicst */
	/* for this purpose we use the quad PTASSIGN, that assigns value to pointed cells */
	/* size of word is 4 byte */
	gen(newQuad(Q_PTASSIGN_CST,$3,$$,(void*)(i*4)));
      }
}

ATOMICCST : tok_num {
  /* create a new cst and hold pointer */
 symbol news=newSymbol(S_CST,&($1),TYPE_INT);
  $$=addSymbol(news);
}
| tok_op tok_minus tok_num tok_cp {
  /* create a new cst and hold pointer */
  int val=-$3;
  symbol news=newSymbol(S_CST,&(val),TYPE_INT);
  $$=addSymbol(news);
}
| tok_true {
  /* create a new cst and hold pointer */
  int val=1;
  symbol news=newSymbol(S_CST,&(val),TYPE_BOOL);
  $$=addSymbol(news);
  }
| tok_false {
  /* create a new cst and hold pointer */
  int val=0;
  symbol news=newSymbol(S_CST,&(val),TYPE_BOOL);
  $$=addSymbol(news);
  }

ARGLIST : tok_op tok_cp {
  pushContext();
}
| ARGLIST1 {
  pushContext();
  addBunchOfSymbols($1);
}

ARGLIST1 : tok_op ARG tok_cp {
  $$=cons_s(nil_s(),$2);
}
| tok_op ARG tok_cp ARGLIST1 {
  $$=cons_s(nil_s(),$2);
  $$=concat_s($$,$4);
}

ARG : tok_ident tok_colon TYPE {
  $$=newSymbol(S_ID,$1,$3);
}
| tok_ident tok_colon ATOMICTYPE tok_ref {
  if ($3==TYPE_INT)
    {
      addSymbol(newSymbol(S_ID,$1,TYPE_INT_REF));
    }
  else
    {
      addSymbol(newSymbol(S_ID,$1,TYPE_BOOL_REF));
    }
}

INSTR : tok_if EXPR tok_then M INSTR %prec NO_ELSE_REDUCE {
  if ($2.valType!=TYPE_BOOL)
    {
      error(TYPE,TYPE_BOOL,__LINE__);
    }
  backpatch($2.truelist,$4);
  $$.nextlist=concat_i($2.falselist,$5.nextlist);
  }
| tok_if EXPR tok_then M INSTR tok_else M INSTR {
  if ($2.valType!=TYPE_BOOL)
    {
      error(TYPE,TYPE_BOOL,__LINE__);
    }
  backpatch($2.truelist,$4);
  backpatch($2.falselist,$7);
  $$.nextlist=concat_i($5.nextlist,$8.nextlist);
}
| tok_while M EXPR tok_do M SEQUENCE tok_done {
  if ($3.valType!=TYPE_BOOL)
    {
      error(TYPE,TYPE_BOOL,__LINE__);
    }
  backpatch($3.truelist,$5);
  backpatch($6.nextlist,$2);
  $$.nextlist=$3.falselist;
}
| tok_begin SEQUENCE tok_end {
  $$.nextlist=$2.nextlist;
}
| tok_begin tok_end {
  $$.nextlist=nil_i();
}
| tok_ident tok_aff EXPR {
  /* here we add ident to the symbol table if it isn't already */
  symbol* ptr=searchSymbol($1);
  if (ptr == SYMBOL_NOT_FOUND)
    {
      symbol news=newSymbol(S_ID,strdup($1),$3.valType);
      ptr=addSymbol(news);
    }
  /* free the char* allocated in yylval */
  free($1);
  
  /* that is for ref instead... */
  /* if (ptr->valType!=$3.valType) */
  /*   { */
  /*     error(TYPE,TYPE_BOOL,__LINE__); */
  /*   } */

  /* also keep next list of expr if it has one */
  if($3.valType==TYPE_BOOL)
    {
      /* if expr is a bool we translate using syntax from b = boolexpr */
      /* to if (boolexpr) then b=true else b=false */
      unsigned long int trueAffCodePtr=gen(newQuad(Q_ASSIGN,getPtrToTrueCst(),NULL,ptr));
      unsigned long int gotonext1=gen(newQuad(Q_GOTO,NULL,NULL,NULL));
      unsigned long int falseAffCodePtr=gen(newQuad(Q_ASSIGN,getPtrToFalseCst(),NULL,ptr));
      unsigned long int gotonext2=gen(newQuad(Q_GOTO,NULL,NULL,NULL));
      backpatch($3.truelist,trueAffCodePtr);
      backpatch($3.falselist,falseAffCodePtr);
      /* add unfilled jump to next list */
      $$.nextlist=cons_i(cons_i(nil_i(),gotonext1),gotonext2);
    }
  else 
    {
      /* gen quad for affectation */
      gen(newQuad(Q_ASSIGN,$3.ptrVal,NULL,ptr));
      $$.nextlist=nil_i();
    }
}
| tok_ident tok_dot tok_op EXPR tok_cp tok_leftArrow EXPR {
  $$.nextlist=nil_i();
}
| tok_printInt EXPR {
  if($2.valType==TYPE_BOOL)
    {
      error(TYPE,TYPE_INT,__LINE__);
    }

  $$.nextlist=nil_i();
  /* gen quad for affectation */
  gen(newQuad(Q_PRINTI,$2.ptrVal,NULL,NULL));
}
| tok_printString tok_string {
  symbol news=newSymbol(S_CST,$2,TYPE_STR);
  symbol* sym=addSymbol(news);
  gen(newQuad(Q_PRINTS,sym,NULL,NULL));
  $$.nextlist=nil_i();
}

/* protocol can only be called within begin/end */
SEQUENCE : INSTR {
  $$.nextlist=$1.nextlist;
}
| PROCCALL {
  $$.nextlist=$1.nextlist;
  }
| SEQUENCE tok_sep M PROCCALL {
  backpatch($1.nextlist,$3);
  $$.nextlist=$4.nextlist;
}
| SEQUENCE tok_sep M INSTR {
  backpatch($1.nextlist,$3);
  $$.nextlist=$4.nextlist;
}

PROCCALL : tok_ident EXPRLIST {
  symbol* ptr=searchSymbol($1);
  if (ptr==SYMBOL_NOT_FOUND)
    {
      error(SYMBOL,SYMBOL_FOUND,__LINE__);
    }
  $$.nextlist=$2.nextlist;

  /* see quad.h for Q_CALL members definition */
  /* no return */
  /* but parameters! number held in exprlist */
  gen(newQuad(Q_CALL,NULL,ptr,(void*)$2.number));

}
| tok_ident tok_op tok_cp {
  symbol* ptr=searchSymbol($1);
  if (ptr==SYMBOL_NOT_FOUND)
    {
      error(SYMBOL,SYMBOL_FOUND,__LINE__);
    }
  $$.nextlist=nil_i();

  /* no return */
  /* no parameters */
  /* see quad.h for Q_CALL members definition */
  gen(newQuad(Q_CALL,NULL,ptr,(void*)0));

}

EXPR : tok_num {
  symbol news = newSymbol(S_CST,&($1),TYPE_INT);
  $$.ptrVal = addSymbol(news);
  $$.valType=TYPE_INT;
  }
| tok_true {
  /* save symbol by using the const one stored in symbol table */
  $$.ptrVal=getPtrToTrueCst();

  /* create goto quad and add its index in the truelist =) */
  $$.truelist=cons_i(nil_i(),gen(newQuad(Q_GOTO,NULL,NULL,NULL)));
  /* falselist is empty */
  $$.falselist=nil_i();

  $$.valType=TYPE_BOOL;
  }
| tok_false {
  /* save symbol by using the const one stored in symbol table */
  $$.ptrVal=getPtrToFalseCst();

  /* create goto quad and add its index in the falselist =) */
  $$.falselist=cons_i(nil_i(),gen(newQuad(Q_GOTO,NULL,NULL,NULL)));
  /* truelist is empty */
  $$.truelist=nil_i();

  $$.valType=TYPE_BOOL;
  }
| tok_if EXPR tok_then M EXPR %prec NO_ELSE_REDUCE {
  if ($2.valType!=TYPE_BOOL)
    {
      error(TYPE,TYPE_BOOL,__LINE__);
    }
  backpatch($2.truelist,$4);

  /* our EXPR has the type of the returned expr */
  $$.valType=$5.valType;
  if($$.valType==TYPE_BOOL)
    {
      $$.truelist=$5.truelist;
      $$.falselist=concat_i($2.falselist,$5.falselist);
    }
 }
| tok_if EXPR tok_then M EXPR tok_else M EXPR  {

  if ($2.valType!=TYPE_BOOL)
    {
      error(TYPE,TYPE_BOOL,__LINE__);
    }
  /* return type have to be the same */
  if ($5.valType!=$8.valType)
    {
      error(TYPE,$5.valType,__LINE__);
    }

  backpatch($2.truelist,$4);
  backpatch($2.falselist,$7);


  /* our EXPR has the type of the returned expr */
  $$.valType=$5.valType;
  if($$.valType==TYPE_BOOL)
    {
      /* whatever the expression leads to, we just take old lists */
      $$.truelist=concat_i($5.truelist,$8.truelist);
      $$.falselist=concat_i($5.falselist,$8.falselist);
    }
  else
    {
      /* previous expr were int so nil truelist and falselist */
      $$.truelist=nil_i();
      $$.falselist=nil_i();
    }
 }
| tok_op EXPR tok_cp {
  $$.valType = $2.valType;
  $$.ptrVal = $2.ptrVal;
  $$.truelist=$2.truelist;
  $$.falselist=$2.falselist;
 }
| EXPR tok_add EXPR {
  assert($1.ptrVal);
  assert($3.ptrVal);
  if (($1.valType!=TYPE_INT)||($3.valType!=TYPE_INT))
    {
      error(TYPE,TYPE_INT,__LINE__);
    }
  $$.ptrVal=newTmp(TYPE_INT);
  $$.valType=TYPE_INT;
  gen(newQuad(Q_ADDI,$1.ptrVal,$3.ptrVal,$$.ptrVal));
 }
| EXPR tok_minus EXPR {
  assert($1.ptrVal);
  assert($3.ptrVal);
  if (($1.valType!=TYPE_INT)||($3.valType!=TYPE_INT))
    {
      error(TYPE,TYPE_INT,__LINE__);
    }
  $$.ptrVal=newTmp(TYPE_INT);
  $$.valType=TYPE_INT;
  gen(newQuad(Q_MINI,$1.ptrVal,$3.ptrVal,$$.ptrVal));
 }
| EXPR tok_mul EXPR {
  assert($1.ptrVal);
  assert($3.ptrVal);
  if (($1.valType!=TYPE_INT)||($3.valType!=TYPE_INT))
    {
      error(TYPE,TYPE_INT,__LINE__);
    }
  $$.ptrVal=newTmp(TYPE_INT);
  $$.valType=TYPE_INT;
  gen(newQuad(Q_MULI,$1.ptrVal,$3.ptrVal,$$.ptrVal));
 }
| EXPR tok_div EXPR {
  assert($1.ptrVal);
  assert($3.ptrVal);
  if (($1.valType!=TYPE_INT)||($3.valType!=TYPE_INT))
    {
      error(TYPE,TYPE_INT,__LINE__);
    }
  $$.ptrVal=newTmp(TYPE_INT);
  $$.valType=TYPE_INT;
  gen(newQuad(Q_DIVI,$1.ptrVal,$3.ptrVal,$$.ptrVal));
 }
| EXPR tok_eq EXPR {
  if (($1.valType!=TYPE_INT)||($3.valType!=TYPE_INT))
    {
      error(TYPE,TYPE_INT,__LINE__);
    }
  $$.valType=TYPE_BOOL;

  /* create quad for the rel hold in $2 */
  /* gen code and get address */
  unsigned long int codeptr=gen(newQuad(Q_IFEQGOTO,$1.ptrVal,$3.ptrVal,NULL));
  /* add adress to the truelist */
  $$.truelist=cons_i(nil_i(),codeptr);
  /* same for falselist, next instruction */
  codeptr=gen(newQuad(Q_GOTO,NULL,NULL,NULL));
  $$.falselist=cons_i(nil_i(),codeptr);
}
| EXPR tok_rel EXPR {
  if (($1.valType!=TYPE_INT)||($3.valType!=TYPE_INT))
    {
      error(TYPE,TYPE_INT,__LINE__);
    }
  $$.valType=TYPE_BOOL;

  /* gen code and get address */
  /* token_rel holds rel operator */
  unsigned long int codeptr=gen(newQuad($2,$1.ptrVal,$3.ptrVal,NULL));
  /* add adress to the truelist */
  $$.truelist=cons_i(nil_i(),codeptr);
  /* same for falselist, next instruction */
  codeptr=gen(newQuad(Q_GOTO,NULL,NULL,NULL));
  $$.falselist=cons_i(nil_i(),codeptr);
}
| EXPR tok_andAnd M EXPR {
  if (($1.valType!=TYPE_BOOL)||($4.valType!=TYPE_BOOL))
    {
      error(TYPE,TYPE_BOOL,__LINE__);
    }
  $$.valType=TYPE_BOOL;

  backpatch($1.truelist,$3);
  $$.falselist=concat_i($1.falselist,$4.falselist);
  $$.truelist=$4.truelist;
}
| EXPR tok_orOr M EXPR {
  /* both are bool, they don't have ptr */
  if (($1.valType!=TYPE_BOOL)||($4.valType!=TYPE_BOOL))
    {
      error(TYPE,TYPE_BOOL,__LINE__);
    }
  $$.valType=TYPE_BOOL;
  backpatch($1.falselist,$3);
  $$.truelist=concat_i($1.truelist,$4.truelist);
  $$.falselist=$4.falselist;
}
| tok_minus EXPR %prec tok_not {
  assert($2.ptrVal);
  if ($2.ptrVal->valType!=TYPE_INT)
    {
      error(TYPE,TYPE_INT,__LINE__);
    }

  /* create a new entry in symbol table */
  $$.ptrVal=newTmp(TYPE_INT);
  /* result of this -x is a qnegate */
  gen(newQuad(Q_NEGATE,$2.ptrVal,NULL,$$.ptrVal));
 }
| tok_not EXPR {
  if ($2.valType!=TYPE_BOOL)
    {
      error(TYPE,TYPE_BOOL,__LINE__);
    }
  $$.valType=TYPE_BOOL;
  /* the ptr is the same */
  $$.ptrVal=$2.ptrVal;
  /* but we reverse truelist and falselist */
  $$.truelist=$2.falselist;
  $$.falselist=$2.truelist;
 }
| tok_readInt tok_op tok_cp {
  $$.ptrVal=newTmp(TYPE_INT);
  $$.valType=$$.ptrVal->valType;
  gen(newQuad(Q_READI,NULL,NULL,$$.ptrVal));
 }
| tok_ident {
  $$.ptrVal = searchSymbol($1);
  if ($$.ptrVal == SYMBOL_NOT_FOUND)
    {
      error(SYMBOL,SYMBOL_FOUND,__LINE__);
    }
  if($$.ptrVal->valType==TYPE_BOOL)
    {
      /* if true we might jump somewhere */
      unsigned long int codeptr=gen(newQuad(Q_GOTO,NULL,NULL,NULL));
      $$.truelist=cons_i(nil_i(),codeptr);
      /* otherwise just reading the code linear manner */
      $$.falselist=nil_i();
    }
  $$.valType=$$.ptrVal->valType;

  /* free the char* allocated in yylval */
  free($1);
  }
| tok_exclam tok_ident {
  symbol* ptr=searchSymbol($2);
  if (ptr==SYMBOL_NOT_FOUND)
    {
      error(SYMBOL,SYMBOL_FOUND,__LINE__);
    }
  enum val_t idType=ptr->valType;
  if (idType==TYPE_BOOL_REF) {
    $$.ptrVal=newTmp(TYPE_BOOL);
    $$.truelist=nil_i();
    $$.falselist=nil_i();
  }
  else if (idType==TYPE_INT_REF)
    $$.ptrVal=newTmp(TYPE_INT);
  else
    {
      /* or bool ref, whatever ref */
      error(TYPE,TYPE_INT_REF,__LINE__);
    }
  $$.valType=$$.ptrVal->valType;
  /* gen the quad for assignement, here offset is immediate const*/
  gen(newQuad(Q_PTASSIGN_CST,ptr,$$.ptrVal,(void*)0));

  /* free the char* allocated in yylval */
  free($2);
 }
| tok_ident tok_dot tok_op EXPR tok_cp {
  /* the array has to be defined before */
  symbol* ptr=searchSymbol($1);
  if (ptr==SYMBOL_NOT_FOUND)
    {
      error(SYMBOL,SYMBOL_FOUND,__LINE__);
    }
  /* it has to be an array */
  enum val_t idType=ptr->valType;
  if (idType==TYPE_BOOL_ARRAY) {
    $$.truelist=nil_i();
    $$.falselist=nil_i();
    $$.ptrVal=newTmp(TYPE_BOOL);
  }
  else if (idType==TYPE_INT_ARRAY) {
    $$.ptrVal=newTmp(TYPE_INT);
  }
  else
    {
      /* or bool array, whatever array */
      error(TYPE,TYPE_INT_ARRAY,__LINE__);
    }
  $$.valType=$$.ptrVal->valType;
  /* add offset to the symbol table */
  symbol* offset = newTmp(TYPE_INT);
  gen(newQuad(Q_MULI,$4.ptrVal,getPtrToWordSize(),offset));
  /* gen code such that the value of this cell is assigned to $$.ptrVal */
  /* here is offset is pointed by a symbol */
  gen(newQuad(Q_PTASSIGN,ptr,$$.ptrVal,offset));

  /* free the char* allocated in yylval */
  free($1);
 }
| tok_ident EXPRLIST %prec FUNC_CALL_REDUCE {
  symbol* ptr=searchSymbol($1);
  if (ptr==SYMBOL_NOT_FOUND)
    {
      error(SYMBOL,SYMBOL_FOUND,__LINE__);
    }
  if (ptr->valType==TYPE_BOOL)
    {
      $$.truelist=nil_i();
      $$.falselist=nil_i();
    }
  /* fetch return type of the function */
  /* and create a new tmp that holds result of the function */
  $$.ptrVal=newTmp(ptr->valType);
  $$.valType=$$.ptrVal->valType;
  /* see quad.h for Q_CALL members definition */
  gen(newQuad(Q_CALL,$$.ptrVal,ptr,(void*)$2.number));

  /* free the char* allocated in yylval */
  free($1);
 }
| tok_ident tok_op tok_cp {
  symbol* ptr=searchSymbol($1);
  if (ptr==SYMBOL_NOT_FOUND)
    {
      error(SYMBOL,SYMBOL_FOUND,__LINE__);
    }
  if (ptr->valType==TYPE_BOOL)
    {
      $$.truelist=nil_i();
      $$.falselist=nil_i();
    }
  /* fetch return type of the function */
  /* and create a new tmp that holds result of the function */
  $$.ptrVal=newTmp(ptr->valType);
  $$.valType=$$.ptrVal->valType;
  /* see quad.h for Q_CALL members definition */
  gen(newQuad(Q_CALL,$$.ptrVal,ptr,(void*)0));

  /* free the char* allocated in yylval */
  free($1);
}


EXPRLIST : EXPR %prec EXPRLIST_REDUCE {
  if($1.valType==TYPE_BOOL)
    {
      /* exprlist for function call: we don't care whether expression is true or false now */
      /* just complete the quads such that evaluation is linear (go to next quad) */
      $$.nextlist=concat_i($1.truelist,$1.falselist);
    }
  else
    {
      $$.nextlist=nil_i();
    }
  /* number of parameters is 1 */
  $$.number=1;
  gen(newQuad(Q_PARAM,$1.ptrVal,NULL,NULL));
}
| EXPRLIST M EXPR %prec EXPRLIST_REDUCE {
  backpatch($1.nextlist,$2);
  if($3.valType==TYPE_BOOL)
    {
      /* exprlist for function call: we don't care whether expression is true or false now */
      /* just complete the quads such that evaluation is linear (go to next quad) */
      $$.nextlist=concat_i($3.truelist,$3.falselist);
    }
  else
    {
      $$.nextlist=nil_i();
    }
  /* number of arguments + 1 */
  $$.number=$1.number+1;
  gen(newQuad(Q_PARAM,$3.ptrVal,NULL,NULL));
}

%%

void yyerror (const char* err)
{
  printf("err: %s\n",err);
  exit(1);
  return;
}


